﻿using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Text;

namespace Language.Syntax.Colouring
{
    internal class DatabaseClassifier
    {
        #region Private Data

        private Scc.Connection _connection;
        private Stub.Database _database;

        private ClassificationTypes _classificationTypes;
        private Parser.Scc _sccParser;

        private Dictionary<ITextSnapshot, SortedList<int, ResolvedClassification>> _classifications = new Dictionary<ITextSnapshot, SortedList<int, ResolvedClassification>>();

        private ITextSnapshot _mostUpToDateSnapshot;
        private ITextSnapshot _mostRecentlyRequestedSnapshot;

        #endregion Private Data

        #region Public Properties

        public string RelativeFilePath => _sccParser.FilePath.Relative;
        public ITextSnapshot MostUpToDateSnapshot => _mostUpToDateSnapshot;
        public SortedList<int, ResolvedClassification> this[ ITextSnapshot snapshot ]
        {
            get { _mostRecentlyRequestedSnapshot = snapshot; return _classifications[ snapshot ]; }
        }

        #endregion Public Properties

        #region C-Tor

        public DatabaseClassifier( Scc.Connection connection, Stub.Database database, ClassificationTypes classificationTypes, ITextBuffer textBuffer )
        {
            _connection = connection;
            _database = database;

            _classificationTypes = classificationTypes;

            _sccParser = new Parser.Scc( textBuffer, _connection, _database );
            _sccParser.ParseComplete += _sccParser_ParseComplete;
        }

        #endregion C-Tor

        #region Public Methods

        public bool TryGetClassifications( ITextSnapshot snapshot, out SortedList<int, ResolvedClassification> classifications )
        {
            _mostRecentlyRequestedSnapshot = snapshot;
            return _classifications.TryGetValue( snapshot, out classifications );
        }

        #endregion Public Methods

        #region Private Methods

        private void RemoveOldSnapshots()
        {
            if ( _mostRecentlyRequestedSnapshot == null )
                return;

            var keys = _classifications.Keys.ToList();

            foreach ( var key in keys )
            {
                if ( key.Version.VersionNumber < _mostRecentlyRequestedSnapshot.Version.VersionNumber )
                {
                    _classifications.Remove( key );
                }
            }
        }

        #endregion Private Methods

        #region Event Handlers

        private async void _sccParser_ParseComplete( SnapshotSpan snapshotSpan, ITextSnapshot snapshot )
        {
            ClassificationResolver classifier = new ClassificationResolver( _sccParser.FilePath.Relative, _database, _classificationTypes );

            await Task.Run( () => classifier.Scan( snapshot ) );

            _classifications[ snapshot ] = classifier.Classifications;
            _mostUpToDateSnapshot = snapshot;

            RemoveOldSnapshots();

            NewSnapshotAvailable?.Invoke( snapshot );
        }

        #endregion Event Handlers

        #region Events

        public delegate void NewSnapshotAvailableHandler( ITextSnapshot snapshot );
        public event NewSnapshotAvailableHandler NewSnapshotAvailable;

        #endregion Events
    }
}
